package com.example.mockito;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.MockingDetails;
import org.mockito.Mockito;
import org.mockito.exceptions.verification.NoInteractionsWanted;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Answers.CALLS_REAL_METHODS;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.*;

public class SerializableMocks {

    /**
     * 用于web之间传输
     */
    @DisplayName("Serializable")
    @Test
    void serializable() {
        List<Object> list = new ArrayList<Object>();
        List<Object> spy = mock(ArrayList.class, withSettings()
                .spiedInstance(list)
                .defaultAnswer(CALLS_REAL_METHODS)
                .serializable());
    }

    @DisplayName("Verification ignoring stubs (Since 1.9.0)")
    @Test
    void ignoringStubs() {
        //mocking lists for the sake of the example (if you mock List in real you will burn in hell)
        List mock1 = mock(List.class), mock2 = mock(List.class);
        //stubbing mocks:
        when(mock1.get(0)).thenReturn(10);
        when(mock2.get(0)).thenReturn(20);

        // using mocks by calling stubbed get(0) methods:
        Assertions.assertEquals(mock1.get(0), 10);
        Assertions.assertEquals(mock2.get(0), 20);

        //using mocks by calling clear() methods:
        mock1.clear();
        mock2.clear();

        //verification:
        verify(mock1).clear();
        verify(mock2).clear();


        verify(mock1).get(0);
        //mock的api，没有需要验证的
        verifyNoMoreInteractions(mock1);

        //官方不推荐使用 否则容易出现不可以维护
        //verify(mock2).get(0);
        assertThrows(NoInteractionsWanted.class, () -> {
            // mock定义的get(0)没有验证[verify(mock2).get(0)];
            verifyNoMoreInteractions(mock2);
        });

        //However, if we ignore stubbed methods then we can verifyNoMoreInteractions()
        verifyNoMoreInteractions(ignoreStubs(mock2));

        //Remember that ignoreStubs() *changes* the input mocks and returns them for convenience.
    }

    @DisplayName("mock 详细信息")
    @Test
    void testMockingDetails() {
        //To identify whether a particular object is a mock or a spy:
        List mockList = mock(List.class);
        assertTrue(mockingDetails(mockList).isMock());
        assertTrue(mockingDetails(spy(List.class)).isMock());
        assertFalse(mockingDetails(new Object()).isMock());

        //Getting details like type to mock or default answer:
        MockingDetails details = mockingDetails(mockList);
        details.getMockCreationSettings().getTypeToMock();
        details.getMockCreationSettings().getDefaultAnswer();

        //Getting invocations and stubbings of the mock:
        details.getInvocations();
        details.getStubbings();
        when(mockList.get(0)).thenReturn(0);
        //Printing all interactions (including stubbing, unused stubs)
        System.out.println("printInvocations: " + mockingDetails(mockList).printInvocations());
    }
}
